package pay

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/go-pay/util"
	"github.com/go-pay/xlog"

	"github.com/gin-gonic/gin"
	"net/http"
	"os"
	"sale-admin/config"
	"sale-admin/internal/pkg"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	"github.com/go-pay/gopay"

	"github.com/go-pay/gopay/wechat"
	wechatv3 "github.com/go-pay/gopay/wechat/v3"
)

const (
	Success = 0
)

// ComplaintNotifyData 投诉通知解密后的数据结构
type ComplaintNotifyData struct {
	ComplaintID string `json:"complaint_id"`
	ActionType  string `json:"action_type"`
}

type WechatPay struct {
	feiShuWebhook pkg.FeiShuWebhook
}

var (
	WechatClient   *wechat.Client
	WechatClientV3 *wechatv3.ClientV3
)

func (wp WechatPay) ConfigInit(appId, mchId, apiKey, cert string) (err error) {
	// 初始化微信客户端
	//    appId：应用ID
	//    mchId：商户ID
	//    apiKey：API秘钥值
	//    isProd：是否是正式环境
	WechatClient = wechat.NewClient(appId, mchId, apiKey, true)

	// 打开Debug开关，输出日志
	WechatClient.DebugSwitch = gopay.DebugOn
	// 添加pkcs12内容
	err1 := WechatClient.AddCertPkcs12FilePath(cert)
	if err1 != nil {
		err = errorx.New("微信证书文件写入出错", -1)
		logx.Error(context.Background(), "wechat config init", logx.Any("微信证书文件写入出错", err1.Error()))
		return
	}
	return
}

// 微信V3初始化
func (wp WechatPay) V3ConfigInit(MchId, SerialNo, APIv3Key string) (err error) {
	// NewClientV3 初始化微信客户端 V3
	//	mchid：商户ID
	// 	serialNo：商户证书的证书序列号
	//	apiV3Key：APIv3Key，商户平台获取
	//	privateKey：商户API证书下载后，私钥 apiclient_key.pem 读取后的字符串内容
	if MchId == "" {
		MchId = config.Config.WechatV3Config.MchID
	}
	if SerialNo == "" {
		SerialNo = config.Config.WechatV3Config.SerialNo
	}
	if APIv3Key == "" {
		APIv3Key = config.Config.WechatV3Config.APIv3Key
	}
	PrivateKeyContent, _ := os.ReadFile(config.Config.WechatV3Config.ApiclientKey)
	WechatClientV3, err = wechatv3.NewClientV3(MchId, SerialNo, APIv3Key, string(PrivateKeyContent))
	if err != nil {
		logx.Error(context.Background(), "wechat config init", logx.Any("NewClientV3 err", err.Error()))
		return
	}

	// 设置微信平台证书和序列号，如开启自动验签，请忽略此步骤
	//client.SetPlatformCert([]byte(""), "")

	// [ERROR] >> GetAndSelectNewestCert() failed or certs is empty: &{Code:401 Certs:[] Error:{"code":"SIGN_ERROR","message":"商户未设置加密的密钥，请登录商户平台操作！请参考http://kf.qq.com/faq/180830E36vyQ180830AZFZvu.html"}}

	// 启用自动同步返回验签，并定时更新微信平台API证书
	err = WechatClientV3.AutoVerifySign()
	if err != nil {
		logx.Error(context.Background(), "wechat config init", logx.Any("AutoVerifySign err", err.Error()))
		return
	}

	// 打开Debug开关，输出日志
	WechatClientV3.DebugSwitch = gopay.DebugOff
	return nil
}

type WechatNativePayRsp struct {
	ReturnCode string `json:"return_code"`
	ReturnMsg  string `json:"return_msg"`
	Appid      string `json:"appid"`
	SubAppid   string `json:"sub_appid"`
	MchId      string `json:"mch_id"`
	SubMchId   string `json:"sub_mch_id"`
	DeviceInfo string `json:"device_info"`
	NonceStr   string `json:"nonce_str"`
	Sign       string `json:"sign"`
	ResultCode string `json:"result_code"`
	ErrCode    string `json:"err_code"`
	ErrCodeDes string `json:"err_code_des"`
	TradeType  string `json:"trade_type"`
	PrepayId   string `json:"prepay_id"`
	CodeUrl    string `json:"code_url"`
	MwebUrl    string `json:"mweb_url"`
	Timestamp  string `json:"timestamp"`
	PaySign    string `json:"paySign"`
}

// outTradeNo 订单号
// amount 总金额
func (wp WechatPay) NativePay(remoteIP, outTradeNo string, amount int64, apiKey string) (rsp wechat.UnifiedOrderResponse, err error) {
	// 初始化参数Map
	bm := make(gopay.BodyMap)
	bm.Set("nonce_str", util.RandomString(32)).
		Set("body", "大道支付").
		Set("out_trade_no", outTradeNo).
		Set("total_fee", amount).
		Set("spbill_create_ip", remoteIP).
		Set("notify_url", config.Config.WechatNotifyUrl). //回调地址
		Set("trade_type", wechat.TradeType_Native).
		Set("device_info", "WEB").
		Set("sign_type", wechat.SignType_MD5).
		SetBodyMap("scene_info", func(bm gopay.BodyMap) { //场景信息
			bm.Set("id", "123") //门店编号
		})

	logx.Info(context.Background(), "wechat native pay", logx.Any("outTradeNo", outTradeNo))
	// 请求支付下单，成功后得到结果
	wxRsp, err := WechatClient.UnifiedOrder(context.Background(), bm)
	if err != nil {
		logx.Error(context.Background(), "client.UnifiedOrder error", logx.Any("bm", bm), logx.Any("err", err))
		return
	}

	return *wxRsp, err
}

func (wp WechatPay) QueryOrder(outTradeNo string) (rsp wechat.QueryOrderResponse, err error) {
	// 初始化参数结构体
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", outTradeNo).
		Set("nonce_str", util.RandomString(32)).
		Set("sign_type", wechat.SignType_MD5)

	// 请求订单查询，成功后得到结果
	wxRsp, resBm, err := WechatClient.QueryOrder(context.Background(), bm)
	if err != nil {
		logx.Error(context.Background(), "client.QueryOrder error", logx.Any("bm", bm), logx.Any("resBm", resBm), logx.Any("err", err))
		return
	}
	return *wxRsp, nil
}

func (wp WechatPay) OrderClose(outTradeNo string) (rsp wechat.CloseOrderResponse, err error) {
	// 初始化参数结构体
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", outTradeNo).
		Set("nonce_str", util.RandomString(32)).
		Set("sign_type", wechat.SignType_MD5)

	// 请求关闭订单，成功后得到结果
	wxRsp, err := WechatClient.CloseOrder(context.Background(), bm)
	if err != nil {
		logx.Error(context.Background(), "client.CloseOrder error", logx.Any("bm", bm), logx.Any("err", err))
		return
	}
	return *wxRsp, nil
}

func (wp WechatPay) Refund(outTradeNo string, amount, refundAmount int64) (rsp wechat.RefundResponse, err error) {
	outRefundNo := util.RandomString(64)
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", outTradeNo).
		Set("nonce_str", util.RandomString(32)).
		Set("sign_type", wechat.SignType_MD5).
		Set("out_refund_no", outRefundNo).
		Set("total_fee", amount).
		Set("refund_fee", refundAmount)

	wxRsp, resBm, err := WechatClient.Refund(context.Background(), bm)
	if err != nil {
		logx.Error(context.Background(), "client.Refund error", logx.Any("bm", bm), logx.Any("err", err))
		return
	}

	logx.Error(context.Background(), "client.Refund error --- eric测试使用", logx.Any("bm", bm), logx.Any("err", err))

	xlog.Debug("v2-refund-wxRsp:", *wxRsp)
	xlog.Debug("v2-refund-resBm:", resBm)
	return *wxRsp, nil
}

// V3TransactionJsapi js下单返回jsapi参数
// wapp 是否小程序 0否1是
func (wp WechatPay) V3TransactionJsapi(ctx context.Context, outTradeNo string, totalAmount int64, openid, attach string, wapp int) (jsapi *wechatv3.JSAPIPayParams, err error) {
	notifyURL := config.Config.BaseUrl + "/admin/pay/wechat-v3-notify" //回调地址 不能携带参数
	logx.Info(context.Background(), "wechat V3TransactionJsapi", logx.Any("outTradeNo", outTradeNo), logx.Any("notifyURL", notifyURL))
	expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
	if len(attach) > 128 {
		err = errorx.New("附加参数最大128字符", -1)
		return
	}
	var appid string
	if wapp == 1 { // 小程序
		appid = config.Config.WechatMini.AppID
	} else { // 公众号
		appid = pkg.DDZC_APPID
	}
	bm := make(gopay.BodyMap)
	bm.Set("appid", appid).
		Set("out_trade_no", outTradeNo).
		Set("description", "大道智创商品").
		Set("time_expire", expire).
		Set("notify_url", notifyURL).
		Set("attach", attach). //附加参数 最大128字符
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("total", totalAmount).
				Set("currency", "CNY")
		}).
		SetBodyMap("payer", func(bm gopay.BodyMap) {
			bm.Set("openid", openid)
		})

	wxRsp, err1 := WechatClientV3.V3TransactionJsapi(ctx, bm)
	if err1 != nil {
		err = err1
		return
	}
	if wxRsp.Error != "" {
		var wxErr struct {
			Code    string `json:"code"`    // "INVALID_REQUEST"
			Message string `json:"message"` // "201 商户订单号重复"
		}
		json.Unmarshal([]byte(wxRsp.Error), &wxErr)
		err = errorx.New(wxErr.Message, -1)
		return
	}
	if wxRsp.Code == 0 {
		rsp, err := WechatClientV3.PaySignOfJSAPI(appid, wxRsp.Response.PrepayId)
		return rsp, err
	}
	return
}

// V3TransactionQueryOrder v3订单查询接口
func (wp WechatPay) V3TransactionQueryOrder(ctx context.Context, outTradeNo string) (wxRsp wechatv3.QueryOrderRsp, err error) {
	res, err := WechatClientV3.V3TransactionQueryOrder(ctx, 2, outTradeNo)
	return *res, err
}

// V3CloseOrder v3关闭订单
func (wp WechatPay) V3CloseOrder(ctx context.Context, outTradeNo string) (wxRsp wechatv3.CloseOrderRsp, err error) {
	res, err := WechatClientV3.V3TransactionCloseOrder(ctx, outTradeNo)
	return *res, err
}

// V3Refund V3退款
func (wp WechatPay) V3Refund(ctx context.Context, outTradeNo, outRefundNo string, totalAmount, refundAmount int64) (rsp wechatv3.RefundRsp, err error) {
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", outTradeNo).
		Set("out_refund_no", outRefundNo).
		SetBodyMap("amount", func(bm gopay.BodyMap) {
			bm.Set("refund", refundAmount).
				Set("total", totalAmount).
				Set("currency", "CNY")
		})

	res, err := WechatClientV3.V3Refund(ctx, bm)
	return *res, err
}

func (wp WechatPay) V3ComplaintNotify(ctx *gin.Context) (*wechatv3.ComplaintDetailRsp, error) {
	// 解析微信回调请求参数
	notifyReq, err := wechatv3.V3ParseNotify(ctx.Request)
	if err != nil {
		logx.Error(context.Background(), "解析回调请求失败:", logx.Any("err", err))
		ctx.JSON(http.StatusBadRequest, gin.H{"code": "FAIL", "message": "解析请求失败"})
		return nil, err
	}

	// 验证签名
	certMap := WechatClientV3.WxPublicKeyMap()
	err = notifyReq.VerifySignByPKMap(certMap)
	if err != nil {
		logx.Error(context.Background(), "验签失败: %v", logx.Any("err", err))
		ctx.JSON(http.StatusBadRequest, gin.H{"code": "FAIL", "message": "验签失败"})
		return nil, err
	}

	logx.Info(context.Background(), "✅ 回调请求验签成功")

	// 解密回调数据
	var complaintData ComplaintNotifyData
	err = notifyReq.DecryptCipherTextToStruct(string(WechatClientV3.ApiV3Key), &complaintData)
	if err != nil {
		logx.Error(context.Background(), "解密回调数据失败:", logx.Any("err", err))
		ctx.JSON(http.StatusBadRequest, gin.H{"code": "FAIL", "message": "解密数据失败"})
		return nil, err
	}

	var wxDetailRsp *wechatv3.ComplaintDetailRsp
	if complaintData.ComplaintID != "" {
		logx.Info(context.Background(), "收到投诉通知:", logx.Any("complaintData", complaintData))
		wxDetailRsp, err = WechatClientV3.V3ComplaintDetail(ctx.Request.Context(), complaintData.ComplaintID)
		if err != nil {
			return nil, fmt.Errorf("查询投诉详情失败: %v", err)
		}

		if wxDetailRsp.Code != wechatv3.Success {
			return nil, fmt.Errorf("查询投诉详情失败: %s", wxDetailRsp.Error)
		}

		logx.Info(context.Background(), "投诉详情:", logx.Any("wxDetailRsp", wxDetailRsp))
		err = wp.HandleComplaintNotify(ctx.Request.Context(), wxDetailRsp)
		if err != nil {
			logx.Error(context.Background(), "处理投诉通知失败:", logx.Any("err", err))
			return nil, fmt.Errorf("处理投诉通知失败: %v", err)
		}

	} else {
		logx.Error(context.Background(), "未找到投诉ID，请检查回调参数是否正确")
		return nil, fmt.Errorf("未找到投诉ID，请检查回调参数是否正确")
	}
	return wxDetailRsp, nil
}
func (wp WechatPay) HandleComplaintNotify(ctx context.Context, detail *wechatv3.ComplaintDetailRsp) error {
	var txt string
	if detail.Response != nil {
		txt = fmt.Sprintf("收到微信投诉通知，请及时处理\n")
		txt += fmt.Sprintf("投诉ID：%s\n", detail.Response.ComplaintId)
		txt += fmt.Sprintf("投诉内容：%s\n", detail.Response.ComplaintDetail)
		txt += fmt.Sprintf("订单状态：%s\n", detail.Response.ComplaintState)
		txt += fmt.Sprintf("用户投诉次数：%d\n", detail.Response.UserComplaintTimes)
	} else {
		//一般不会为空，但是预防一下
		txt = fmt.Sprintf("收到微信投诉通知，请及时处理")
	}

	if config.Config.Feishu.ComplaintNotifyWebhook != "" {
		err := wp.feiShuWebhook.SendWebhookMessage(config.Config.Feishu.ComplaintNotifyWebhook, txt)
		if err != nil {
			logx.Error(context.Background(), "发送飞书消息失败:", logx.Any("err", err))
			return err
		}
	}

	return nil
}
func (wp WechatPay) SetComplaintNotifyUrl(ctx context.Context, callbackURL string) error {
	if callbackURL == "" {
		//配置为空不处理，测试环境的该字段应该是空的，因为生产和测试用的同一个账号
		return nil
	}

	resp, err := WechatClientV3.V3ComplaintNotifyUrlQuery(ctx)
	if err != nil {
		logx.Error(context.Background(), "V3ComplaintNotifyUrlQuery error", logx.Any("err", err))
		return err
	}

	// 判断配置是否已存在，若不存在且需要创建，则调用create接口创建
	// 判断配置是否已存在，若存在且需要更新，则调用update接口更新
	if resp.Code == 404 || resp.Response.Url == "" {
		if callbackURL != "" {
			// 1. 创建投诉通知回调地址
			respCreate, err := WechatClientV3.V3ComplaintNotifyUrlCreate(ctx, callbackURL)
			if err != nil {
				logx.Error(context.Background(), "V3ComplaintNotifyUrlCreate error", logx.Any("err", err))
				return err
			}

			if respCreate.Code != wechatv3.Success {
				err := fmt.Errorf("V3ComplaintNotifyUrlCreate error: %d %s", respCreate.Code, respCreate.Error)
				logx.Error(context.Background(), "V3ComplaintNotifyUrlCreate error", logx.Any("err", err))
				return err
			}
		}
	} else {
		if callbackURL != "" {
			// 1. 创建投诉通知回调地址
			respUpdate, err := WechatClientV3.V3ComplaintNotifyUrlUpdate(ctx, callbackURL)
			if err != nil {
				logx.Error(context.Background(), "V3ComplaintNotifyUrlUpdate error", logx.Any("err", err))
				return err
			}

			if respUpdate.Code != wechatv3.Success {
				err := fmt.Errorf("V3ComplaintNotifyUrlUpdate error: %d %s", respUpdate.Code, respUpdate.Error)
				logx.Error(context.Background(), "V3ComplaintNotifyUrlUpdate error", logx.Any("err", err))
				return err
			}

			respQuery, err := WechatClientV3.V3ComplaintNotifyUrlQuery(ctx)
			if err != nil {
				logx.Error(context.Background(), "V3ComplaintNotifyUrlQuery error", logx.Any("err", err))
				return err
			}

			if respQuery.Response != nil && respQuery.Response.Url != callbackURL {
				err := fmt.Errorf("V3ComplaintNotifyUrl mismatch, expect: %s, actual: %s", callbackURL, respQuery.Response.Url)
				logx.Error(context.Background(), "V3ComplaintNotifyUrlQuery error",
					logx.Any("err", err))
				return err
			}
		} else {
			//这里要配置的callbackURL为空，调用.V3ComplaintNotifyUrlDelete()删除
			//注意： 这里配置notifyURL为空，不进行删除，因为目前测试环境和正式环境使用同一个微信支付账号，
			//所以，为了避免冲突测试环境该字段会留空，这里不能删除同一账号的回调url
			/*_, err := WechatClientV3.V3ComplaintNotifyUrlDelete(ctx)
			if err != nil {
				logx.Error(context.Background(), "V3ComplaintNotifyUrlDelete error", logx.Any("err", err))
				return err
			}*/
		}
	}
	return err
}
